/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Rewriting;

import SPARQL.Constant;
import SPARQL.Obje;
import SPARQL.Pred;
import SPARQL.Subj;
import SPARQL.TriplePattern;
import SPARQL.Term;
import SPARQL.Variable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author Mirko
 * 
 * 
 */
public class TripleUnifier {

    public TripleUnifier() {
    }
    
    /*
    Qui bisogna modificare il codice in modo tale che se gli atomi hanno alcune variabili uguali (a meno che non siano nella stessa regola) bisogna
    rinominare le variabili in modo tale che non ci sia questo clashing di variabili
    */
    
    private Set<TriplePattern> triples ;
    private Map<Term,Term> unifierGraph;
    private boolean unification;
    
    public TripleUnifier(Set<TriplePattern> tripleP){
        this.triples = tripleP;
        this.unifierGraph = new HashMap<Term, Term>();
        this.unification = false;
        computeUnifier();
    }
    
    public boolean unify(){
    return unification;
        
    }
    public Term maps(Term term1){
       
        return this.unifierGraph.get(term1);
         
    }
    
    public Term unifFunction(Term term){
        Term mappedTerm = term;
        Term iterationTerm = term;
        while (isMapped(iterationTerm)){
            mappedTerm = maps(iterationTerm);
            iterationTerm =  maps(iterationTerm);
            
        }
        return mappedTerm;
    }
    public boolean isMapped(Term term){
        return this.unifierGraph.containsKey(term);
    }
    
    private void insertMap(Term term1 , Term term2){
        this.unifierGraph.put(term1, term2);
    }

    private void computeUnifier() {
        TriplePattern triplePattern1 = null;
        TriplePattern firstTriple = null;
        boolean unify = false;
        Iterator<TriplePattern> iterator = this.triples.iterator();
        if (iterator.hasNext()){
            
            unify = true;
            
            
            triplePattern1 = iterator.next();
            while (iterator.hasNext()){
           
            TriplePattern triplePattern2 = iterator.next();
            //Comparing Subjects
            if (!triplePattern1.getS().equals(triplePattern2.getS())){
                if (unifFunction(triplePattern1.getS()) instanceof Constant && unifFunction(triplePattern2.getS()) instanceof Constant){

                    if (!unifFunction(triplePattern1.getS()).equals(unifFunction(triplePattern2.getS()))){
                        unify = false;
                    return;
                    }

                    }
                else{
                    if (unifFunction(triplePattern1.getS()) instanceof Variable){
                        if (!isMapped(triplePattern1.getS()))
                        this.insertMap(triplePattern1.getS(), triplePattern2.getS());
                        else 
                            insertMap(unifFunction(triplePattern1.getS()) , triplePattern2.getS());
                    }

                    else {
                       if (!isMapped(triplePattern2.getS()))
                        this.insertMap(triplePattern2.getS(), triplePattern1.getS());
                        else 
                            insertMap(unifFunction(triplePattern2.getS()) , triplePattern1.getS());
                    }
                }
            }
            //Comparing Predicates
            if (!triplePattern1.getP().equals(triplePattern2.getP())){
                if (unifFunction(triplePattern1.getP()) instanceof Constant && unifFunction(triplePattern2.getP()) instanceof Constant){

                    if (!unifFunction(triplePattern1.getP()).equals(unifFunction(triplePattern2.getP()))){
                        unify = false;
                    return;
                    }
                    }
                else {
                    if (unifFunction(triplePattern1.getP()) instanceof Variable){
                        if (!isMapped(triplePattern1.getP()))
                        this.insertMap(triplePattern1.getP(), triplePattern2.getP());
                        else 
                            insertMap(unifFunction(triplePattern1.getP()) , triplePattern2.getP());
                    }

                    else {
                       if (!isMapped(triplePattern2.getP()))
                        this.insertMap(triplePattern2.getP(), triplePattern1.getP());
                        else 
                            insertMap(unifFunction(triplePattern2.getP()) , triplePattern1.getP());
                    }
                }
            }
            //Comparing Objects
           if (!triplePattern1.getO().equals(triplePattern2.getO())){
            if (unifFunction(triplePattern1.getO()) instanceof Constant && unifFunction(triplePattern2.getO()) instanceof Constant){

                 if (!unifFunction(triplePattern1.getO()).equals(unifFunction(triplePattern2.getO()))){
                     unify = false;
                 return;
                 }
                 }
            else { 
             if (unifFunction(triplePattern1.getO()) instanceof Variable){
                 if (!isMapped(triplePattern1.getO()))
                 this.insertMap(triplePattern1.getO(), triplePattern2.getO());
                 else 
                     insertMap(unifFunction(triplePattern1.getO()) , triplePattern2.getO());
             }

             else {
                 if (!isMapped(triplePattern2.getO()))
                  this.insertMap(triplePattern2.getO(), triplePattern1.getO());
                  else 
                      insertMap(unifFunction(triplePattern2.getO()) , triplePattern1.getO());
              }
            }
           }
            //for the iteration
            triplePattern1 = triplePattern2;
                
            }
            
            
        }
        
        this.unification = unify;
    }
    
    
    
    
   
}
        
